﻿using System;
using System.Windows;
using System.Collections.Generic;

namespace New3DDemo
{
    public class LineFunc
    {
        private double _a = 0;
        private double _b = 0;
        private bool _special = false;

        // 是否特殊为直线 X = a
        public bool IsSpecial
        {
            get { return _special; }
        }

        // 是否为默认值，可能是默认构造，或构造失败，表示代表值无意义
        public bool IsDefault
        {
            get { return _a == 0 && _b == 0; }
        }

        // 返回直线夹角
        public double Angle
        {
            get
            {
                if (_special)
                    return Math.PI / 2;

                return Math.Atan(_a);
            }
        }

        public LineFunc() { }
        public LineFunc(double argA, double argB)
        {
            _a = argA;
            _b = argB;
        }
        // 构造特殊直线 X = a
        public LineFunc(double argA, bool spec = true)
        {
            _a = argA;
            _special = spec;
        }
        /// <summary>
        /// 通过两点构造一条直线
        /// </summary>
        public LineFunc(Point p1, Point p2)
        {
            // 两个点不能重合
            if (p1.Equals(p2))
                return;

            // 如果两个点在一条垂直线上
            if (p1.X == p2.X)
            {
                _a = p1.X;
                _special = true;
                return;
            }

            _a = (p2.Y - p1.Y) / (p2.X - p1.X);
            _b = p1.Y - _a * p1.X;
        }
        /// <summary>
        /// 根据一个点，和一个角度构造一条直线
        /// </summary>
        public LineFunc(Point p, double angle)
        {
            while (angle > Math.PI / 2) angle -= Math.PI;
            while (angle <= -Math.PI / 2) angle += Math.PI;

            if (angle == Math.PI / 2)
            {
                _a = p.X;
                _special = true;
            }
            else
            {
                _a = Math.Tan(angle);
                _b = p.Y - _a * p.X;
            }
        }
        /// <summary>
        /// 赋值
        /// </summary>
        public void Assign(LineFunc lf)
        {
            _a = lf._a;
            _b = lf._b;
            _special = lf._special;
        }

        /// <summary>
        /// 测试直线是否进过p点
        /// </summary>
        public bool IsPassed(Point p)
        {
            if (_special)
                return Math.Abs(p.X - _a) <= 0.000001;
            return Math.Abs(GetY(p.X) - p.Y) <= 0.000001;
        }
        /// <summary>
        /// 判断两条直线是否平行（重合也算平行）
        /// </summary>
        public bool IsParallel(LineFunc lf)
        {
            return this._a == lf._a || (this._special && lf._special);
        }
        /// <summary>
        /// 获取两条直线的交点
        /// </summary>
        public Point? GetIntersection(LineFunc lf)
        {
            if (IsParallel(lf))
                return null;

            if (_special)
                return lf.GetPointWithX(_a);

            if (lf.IsSpecial)
                return GetPointWithX(lf._a);

            return GetPointWithX((_b - lf._b) / (lf._a - _a));
        }
        /// <summary>
        /// 根据X，计算Y
        /// </summary>
        public double GetY(double x)
        {
            if (_special) return 0;

            return _a * x + _b;
        }
        /// <summary>
        /// 根据x值，获取点
        /// </summary>
        public Point? GetPointWithX(double x)
        {
            if (_special) return null;

            return new Point(x, GetY(x));
        }
        /// <summary>
        /// 根据Y，计算X
        /// </summary>
        public double GetX(double y)
        {
            if (_special) return _a;
            if (_a == 0) return 0;
            return (y - _b) / _a;
        }
        /// <summary>
        /// 根据y值，获取点
        /// </summary>
        public Point? GetPointWithY(double y)
        {
            if (_a == 0 && !_special) return null;

            return new Point(GetX(y), y);
        }

        /// <summary>
        /// 返回与center的x轴距离d的两个点，如果是特殊直线，则返回与y轴距离d的
        /// PS:测试用
        /// </summary>
        public ICollection<Point> GetDoublePointOnLine(Point center, double d)
        {
            if (!IsPassed(center))
                return null;

            ICollection<Point> result = new List<Point>();
            if (_special)
            {
                result.Add(new Point(center.X, center.Y - d));
                result.Add(new Point(center.X, center.Y + d));
            }
            else
            {
                result.Add(GetPointWithX(center.X - d).Value);
                result.Add(GetPointWithX(center.X + d).Value);
            }
            return result;
        }

        /// <summary>
        /// 返回直线边缘的两个点，分别与x和y相交的点
        /// PS:测试用
        /// </summary>
        public ICollection<Point> GetEdgeDoublePoint()
        {
            ICollection<Point> result = new List<Point>();
            if (_special)
            {
                result.Add(GetPointWithY(0).Value);
                result.Add(GetPointWithY(1000).Value);
            }
            else if (_a == 0)
            {
                result.Add(GetPointWithX(0).Value);
                result.Add(GetPointWithX(1000).Value);
            }
            else
            {
                result.Add(GetPointWithX(0).Value);
                result.Add(GetPointWithY(0).Value);
            }
            return result;
        }

        /// <summary>
        /// 旋转直线jiao度（jiao是弧度值），并使其通过p
        /// </summary>
        public void RotaLineAndPassedPoint(Point p, double jiao)
        {
            double j = Angle + jiao;
            while (j > Math.PI / 2) j -= Math.PI;
            while (j <= -Math.PI / 2) j += Math.PI;

            if (j == Math.PI / 2)
            {
                _a = p.X;
                _special = true;
                return;
            }
            else
            {
                _a = Math.Tan(j);
                _b = p.Y - _a * p.X;
                _special = false;
            }
        }
    }
}
